package study.thread.sync;


/*
 * ThreadLocal变量: 和线程同步机制一样，都是为了解决多线程中相同变量的访问冲突问题
 * 
 * (1).在同步机制中，通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的，
 * 使用同步机制要求程序慎密地分析什么时候对变量进行读写，什么时候需要锁定某个对象，什么时候释放对象
 * 锁等繁杂的问题，程序设计和编写难度相对较大。
 * 
 * (2).ThreadLocal 则从另一个角度来解决多线程的并发访问。ThreadLocal 会为每一个线程提供一个独
 * 立的变量副本，从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本，从而也就没
 * 有必要对该变量进行同步了。ThreadLocal 提供了线程安全的共享对象，在编写多线程代码时，可以把不安
 * 全的变量封装进 ThreadLocal。 
 */
public class SequenceNumber {
	// 定义匿名子类创建ThreadLocal的变量
	private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
		// 覆盖初始化方法
		public Integer initialValue() {
			return 0;
		}
	};
	private int it = 0;
	
	public int getIt() {
		return this.it;
	}
	public void setIt(int it) {
		this.it = it;
	}
	public int getNexIt() {
		this.setIt(this.getIt() + 1);
		return this.getIt();
	}
	// 下一个序列号
	public int getNextNum() {
		seqNum.set(seqNum.get() + 1);
		return seqNum.get();
	}

	private static class TestClient extends Thread {
		private SequenceNumber sn;

		public TestClient(SequenceNumber sn) {
			this.sn = sn;
		}

		// 线程产生序列号
		public void run() {
			for (int i = 0; i < 3; i++) {
				System.out.println("thread[" + Thread.currentThread().getName()
						+ "] sn[" + sn.getNextNum() + "]  "+sn.getNexIt());
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws InterruptedException{
		
		SequenceNumber sn = new SequenceNumber();
		System.out.println("end===> "+sn.it);
		// 三个线程产生各自的序列号
		TestClient t1 = new TestClient(sn);
		TestClient t2 = new TestClient(sn);
		TestClient t3 = new TestClient(sn);
		t1.start();
		t2.sleep(4000);
		t2.start();
		System.out.println("end===> "+sn.it);
		
		//t3.start();
		
		//t3.join();
		//t1.join();
		t2.join();
		
		System.out.println("end===> "+sn.it);
	}
}
